home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / prg_casm / snipview.zip / SNIPVIEW.C < prev    next >
C/C++ Source or Header  |  1996-09-16  |  45KB  |  1,293 lines

  1. /*
  2.    SnipView SNIPPETS.NDX-compatible browser contest entry
  3.    Written by Tom Torfs (2:292/516@fidonet.org)
  4.    Donated to the public domain
  5.             
  6.    Date written: 12-Aug-1996
  7.    Last update:  16-Sep-1996
  8.  
  9.    Target operating systems: every operating system VidMgr supports
  10.                              currently: * 16-bit and 32-bit MS-DOS
  11.                                         * 16-bit and 32-bit OS/2
  12.                                         * 32-bit Windows 95/NT
  13.  
  14.    Tested compilers: Watcom C++ 10.6, Borland C++ 3.0
  15.    
  16.    Uses: Andrew Clarke's excellent public domain VidMgr package
  17.    
  18.    General notes:
  19.       * SnipView is strictly ANSI C and should compile without
  20.         problems on all ANSI-compliant compilers; the only
  21.         OS-specific part of it is VidMgr, so Snipview will
  22.         compile and run on all operating systems as long as
  23.         VidMgr-compatible functions are provided
  24.       * for DOS 16-bit it is recommended to compile using
  25.         the compact or large memory model, to avoid
  26.         "not enough memory" errors
  27.       * limits for sections/groups/files/browser/notes are
  28.         easily expandable by changing the LIMITS array, in
  29.         case the snippets ever become really huge
  30.         of course they can be reduced also, for systems low on
  31.         memory (I've set the default limits a lot higher than
  32.         the current requirements)
  33.       * large files that don't fit in memory and/or that exceed
  34.         the number of lines in the LIMITS array, are truncated
  35.       * SnipView works independantly of the screen size (80x25,
  36.         80x50, 40x25, ...). The screen will always be fully used.
  37.         (note that a minimum width of 80 characters and a
  38.          minimum height of 25 lines is highly recommended)
  39.  
  40.    Design notes:
  41.       * both window settings (coordinates, colors etc) and window
  42.         contents of all windows are kept in an array of WINDOW_INFO
  43.         structures (see comments accompanying struct definition for
  44.         more details on the implementation)
  45.       * the file window depends on the group window and the group
  46.         window in turn depends on the section window; check out the
  47.         BuildDependancies() function for more details
  48.       * each extended description line is stored as a separate item
  49.         with an index to the item it belongs to; this makes the rest
  50.         of the implementation (esp. the scrolling routines) much simpler
  51.       * hotkeys are available to jump immediately to a certain window,
  52.         Enter enters a window one level deeper, Esc exits to the
  53.         previous level window, and at all times Alt-X quits the program
  54.         (all these keys are visible on a help bar on the bottom line)
  55.       * all windows scroll if the information doesn't fit on one
  56.         screen, both horizontally and vertically, using the regular
  57.         cursor key controls (arrow keys, pgup/pgdn, home/end)
  58.       * searching for a keyword in all the snippets files is possible,
  59.         with case sensitivity and whole word search being selectable
  60.         
  61.    Naming conventions:
  62.       * typedefs are lowercase if they define a simple data type
  63.         (bool, byte, word, ...), uppercase if they define a complex
  64.         data type (structs etc.)
  65.       * macros, enums, structs and constants are all uppercase,
  66.         distinct parts of compound names are separated by underscores
  67.       * functions are mixed case: the first letter of each distinct
  68.         part is uppercase, the rest lowercase (including first letter)
  69.       * global & static variables are mixed case, but the first letter
  70.         is always lowercase
  71.       * local variables are all lowercase
  72.       (of course these apply only to my own code, not to that of VidMgr
  73.        or the standard library)
  74. */
  75.  
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <string.h>
  79.  
  80. #include "vidmgr.h"
  81.  
  82. #ifdef DOS
  83. /* operating system id from Vidmgr
  84.    manipulated by FindNext() to avoid sluggish searching
  85.    under a multitasker */
  86. extern int opsys_id;
  87. #endif
  88.  
  89. typedef char bool;
  90.  
  91. #ifdef FALSE
  92. #undef FALSE
  93. #endif
  94. #ifdef TRUE
  95. #undef TRUE
  96. #endif
  97.  
  98. enum {FALSE,TRUE};
  99.  
  100. enum {ENTER=0x000D,ESC=0x001B,BACKSPACE=0x0008,DELETE=0x5300,
  101.       ALTX=0x2D00,F1=0x3B00,F2=0x3C00,F3=0x3D00,F4=0x3E00,
  102.       UP=0x4800,DOWN=0x5000,LEFT=0x4B00,RIGHT=0x4D00,
  103.       PGUP=0x4900,PGDN=0x5100,HOME=0x4700,END=0x4F00};
  104.  
  105. enum {NOWINDOW=-1,
  106.       SECTIONWINDOW,GROUPWINDOW,FILEWINDOW,BROWSEWINDOW,NOTEWINDOW,
  107.       WINDOWS};
  108.  
  109. static const short LIMITS[WINDOWS]
  110.    = {64,256,2048,4096,256};
  111.  
  112. static char DEFAULT_INDEXFILE[]
  113.    = "SNIPPETS.NDX";
  114. static char FILE_NOT_FOUND[]
  115.    = "*** File not found ***";
  116. static char FILE_TRUNCATED[]
  117.    = "*** File truncated ***";
  118.    
  119. #define BUFLEN 256
  120. static char  buffer[BUFLEN];
  121.  
  122. static short screenCols;
  123. static short screenRows;
  124.  
  125. static short fileNr = -1;
  126. static char  fileName[13];
  127.  
  128. static char  findString[80];
  129. static short findStringLength = 0;
  130. static bool  findCase = TRUE;
  131. static bool  findWord = FALSE;
  132. static short findFileNr = -1;
  133. static short findLineNr = 0;
  134. static short findColNr = 0;
  135. static bool  found = FALSE;
  136.  
  137. static int   activeWindow;
  138.  
  139. struct WINDOW_INFO
  140. {
  141.    char x1,y1,x2,y2;             /* coordinates */
  142.    char attr;                    /* normal text attribute */
  143.    char attrhigh;                /* highlighted text attribute */
  144.    char attrselected;            /* selected text attribute */
  145.    const char *title;            /* window title */
  146.    short cols;                   /* columns of text */
  147.    short rows;                   /* rows of text */
  148.    short column;                 /* leftmost column on screen (0-based) */
  149.    bool scrollbar;               /* use scroll bar */
  150.    bool exclusive;               /* is window exclusive (fullscreen) */
  151.    short items;                  /* number of items in list */
  152.    short activeitem;             /* currently selected item */
  153.    short firstitem;              /* first item on screen */
  154.    short startitem;              /* current first item in list (inclusive) */
  155.    short enditem;                /* current last item in list (exclusive) */
  156.    char **list;                  /* list of pointers to items */
  157.    short dependingwindow;        /* window that depends on this one */
  158.    short *dependingfirst;        /* first item in depending window */
  159.    bool allowextdescriptions;    /* extended descriptions allowed ? */
  160.    short *descriptionowner;      /* ext. description owner or -1 for none */
  161. };
  162.   
  163. struct WINDOW_INFO window[WINDOWS] =
  164. {
  165.    {1,1,80,7,vm_mkcolor(BLACK,GREEN),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,GREEN),
  166.     "Sections",78,5,0,TRUE,FALSE,0,0,0,0,0,NULL,GROUPWINDOW,NULL,FALSE,NULL},
  167.    {1,8,80,14,vm_mkcolor(BLACK,CYAN),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,CYAN),
  168.     "Groups",78,5,0,TRUE,FALSE,0,0,0,0,0,NULL,FILEWINDOW,NULL,FALSE,NULL},
  169.    {1,15,80,24,vm_mkcolor(LIGHTGRAY,BLUE),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,BLUE),
  170.     "Files",78,8,0,TRUE,FALSE,0,0,0,0,0,NULL,NOWINDOW,NULL,TRUE,NULL},
  171.    {1,1,80,24,vm_mkcolor(LIGHTGRAY,BLUE),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,BLUE),
  172.     fileName,78,22,0,FALSE,TRUE,0,0,0,0,0,NULL,NOWINDOW,NULL,FALSE,NULL},
  173.    {1,1,80,24,vm_mkcolor(LIGHTGRAY,BLUE),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,BLUE),
  174.     "Notes",78,22,0,FALSE,TRUE,0,0,0,0,0,NULL,NOWINDOW,NULL,FALSE,NULL}
  175. };
  176.  
  177. /* edit a string, returns length */
  178. int EditString(int x, int y, char attr, char *s, int maxlen)
  179. {
  180.    int   len;
  181.    int   pos;
  182.    int   key;
  183.    bool  done = FALSE;
  184.    bool  origstring = TRUE;
  185.  
  186.    len = strlen(s);
  187.    pos = len;
  188.    do
  189.    {
  190.       vm_xprintf(x,y,attr,"%-*s",maxlen,s);
  191.       vm_gotoxy(x+pos,y);
  192.       vm_setcursorstyle(CURSORNORM);
  193.       key = vm_getch();
  194.       vm_setcursorstyle(CURSORHIDE);
  195.       switch(key)
  196.       {
  197.       case ENTER:
  198.          done = TRUE;
  199.          break;
  200.       case ESC:
  201.          len = 0;
  202.          s[0] = '\0';
  203.          pos = 0;
  204.          break;
  205.       case BACKSPACE:
  206.          if (pos>0)
  207.          {
  208.             pos--;
  209.             memmove(s+pos,s+pos+1,strlen(s+pos+1)+1);
  210.             len--;
  211.          }
  212.          break;
  213.       case DELETE:
  214.          if (pos<len)
  215.          {
  216.             memmove(s+pos,s+pos+1,strlen(s+pos+1)+1);
  217.             len--;
  218.          }
  219.          break;
  220.       case LEFT:
  221.          if (pos>0)
  222.             pos--;
  223.          break;
  224.       case RIGHT:
  225.          if (pos<len)
  226.             pos++;
  227.          break;
  228.       case HOME:
  229.          pos = 0;
  230.          break;
  231.       case END:
  232.          pos = len;
  233.          break;
  234.       default:
  235.          if (key>=32 && key<=254 && key!=127)
  236.          {
  237.             if (origstring)
  238.             {
  239.                pos = 0;
  240.                len = 0;
  241.             }
  242.             if (len<maxlen)
  243.             {
  244.                if (pos<len)
  245.                   memmove(s+pos+1,s+pos,strlen(s+pos)+1);
  246.                s[pos] = key;
  247.                pos++;
  248.                len++;
  249.             }
  250.             s[len] = '\0';
  251.          }
  252.          break;
  253.       }
  254.       origstring = FALSE;
  255.    }
  256.    while (!done);
  257.    return len;
  258. }
  259.  
  260. /* ask for a yes/no answer */
  261. bool AskYesNo(int x, int y, char attr, char *s, bool def)
  262. {
  263.    bool  yesno;
  264.    bool  done = FALSE;
  265.    int   key;
  266.    
  267.    vm_xprintf(x,y,attr,"%s ? (%c/%c)",s,def?'Y':'y',def?'n':'N');
  268.    vm_gotoxy(x+strlen(s)+9,y);
  269.    do
  270.    {
  271.       vm_setcursorstyle(CURSORNORM);
  272.       key = vm_getch();
  273.       vm_setcursorstyle(CURSORHIDE);
  274.       switch(key)
  275.       {
  276.       case ENTER:
  277.          yesno = def;
  278.          done = TRUE;
  279.          break;
  280.       case 'Y':
  281.       case 'y':
  282.          yesno = TRUE;
  283.          done = TRUE;
  284.          break;
  285.       case 'N':
  286.       case 'n':
  287.          yesno = FALSE;
  288.          done = TRUE;
  289.          break;
  290.       }
  291.    }
  292.    while (!done);
  293.    return yesno;
  294. }
  295.  
  296. /* allocate memory and check for errors */
  297. void MemAlloc(void **ptr, size_t size)
  298. {
  299.    *ptr = malloc(size);
  300.    if (*ptr==NULL)
  301.    {
  302.       printf("Error: not enough memory\n");
  303.       exit(EXIT_FAILURE);
  304.    }
  305. }
  306.  
  307. /* read a single line from a file
  308.    and strip off the newline from the end
  309.    returns lenght of string or EOF if end-of-file */
  310. int ReadLineEof(char *buf, int maxlen, FILE *fp)
  311. {
  312.    int   length;
  313.  
  314.    fgets(buf,maxlen,fp);
  315.    if (feof(fp))
  316.       return EOF;
  317.    /* cut off newline */
  318.    length = strlen(buf)-1;
  319.    buf[length] = '\0';
  320.    return length;
  321. }
  322.  
  323. /* read a single line from a file, handle end-of-file error,
  324.    and strip off the newline from the end */
  325. int ReadLine(char *buf, int maxlen, FILE *fp)
  326. {
  327.    int   length;
  328.  
  329.    length = ReadLineEof(buf,maxlen,fp);
  330.    if (length==EOF)
  331.    {
  332.       printf("Error: unexpected end of file\n");
  333.       exit(EXIT_FAILURE);
  334.    }
  335.    return length;
  336. }
  337.  
  338. /* read & interpret a SNIPPETS.NDX-compatible indexfile */
  339. void ReadIndexFile(const char *indexname)
  340. {
  341.    FILE *ndx;
  342.    int   length;
  343.    int   count;
  344.    bool  done;
  345.    short lastfile = 0;
  346.    
  347.    /* allocate memory */
  348.    for (count=0; count<WINDOWS; count++)
  349.    {
  350.       MemAlloc((void **)&window[count].list,LIMITS[count]*sizeof(char *));
  351.       if (window[count].dependingwindow!=NOWINDOW)
  352.          MemAlloc((void **)&window[count].dependingfirst,LIMITS[count]*sizeof(short));
  353.       if (window[count].allowextdescriptions)
  354.          MemAlloc((void **)&window[count].descriptionowner,LIMITS[count]*sizeof(short));
  355.    }
  356.  
  357.    ndx = fopen(indexname,"r");
  358.    if (ndx==NULL)
  359.    {
  360.       printf("Error: can't read index file %s\n",indexname);
  361.       exit(EXIT_FAILURE);
  362.    }
  363.    
  364.    /* read date information & notes */
  365.    
  366.    length = ReadLine(buffer,BUFLEN,ndx);
  367.    if (memcmp(buffer,"| +++",5)==0)
  368.    {
  369.       length -= 5;
  370.       memmove(buffer,buffer+5,length+1);
  371.       MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],length+1);
  372.       strcpy(window[NOTEWINDOW].list[window[NOTEWINDOW].items],buffer);
  373.       window[NOTEWINDOW].items++;
  374.    }
  375.    
  376.    length = ReadLine(buffer,BUFLEN,ndx);
  377.    if (memcmp(buffer,"| ~~~",5)==0)
  378.    {
  379.       length -= 5;
  380.       memmove(buffer,buffer+5,length+1);
  381.       MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],length+1);
  382.       strcpy(window[NOTEWINDOW].list[window[NOTEWINDOW].items],buffer);
  383.       window[NOTEWINDOW].items++;
  384.       MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],1);
  385.       /* add blank line to separate from notes */
  386.       window[NOTEWINDOW].list[window[NOTEWINDOW].items][0] = '\0';
  387.       window[NOTEWINDOW].items++;
  388.    }
  389.    
  390.    do
  391.       length = ReadLine(buffer,BUFLEN,ndx);
  392.    while (memicmp(buffer,"|NOTES:",7)!=0);     
  393.          
  394.    do
  395.    {
  396.       if (window[NOTEWINDOW].items<LIMITS[NOTEWINDOW])
  397.       {
  398.          MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],length);
  399.          strcpy(window[NOTEWINDOW].list[window[NOTEWINDOW].items],buffer+1);
  400.          window[NOTEWINDOW].items++;
  401.       }
  402.       length = ReadLine(buffer,BUFLEN,ndx);
  403.    }
  404.    while (buffer[0]=='|');
  405.    
  406.    /* section loop */
  407.    
  408.    done = FALSE;
  409.  
  410.    do
  411.    {
  412.       /* read section description */
  413.       
  414.       while (length<2 || buffer[1]!='*')
  415.          length = ReadLine(buffer,BUFLEN,ndx);
  416.      
  417.       window[SECTIONWINDOW].list[window[SECTIONWINDOW].items] = NULL;
  418.       do
  419.       {
  420.          while (length>0 && (ispunct(buffer[0])||isspace(buffer[0])))
  421.             memmove(buffer,buffer+1,length--);
  422.          while (length>0 && (ispunct(buffer[length-1])||isspace(buffer[length-1]))
  423.                          && buffer[length-1]!=')')
  424.             buffer[--length] = '\0';
  425.          if (length>0 && window[SECTIONWINDOW].list[window[SECTIONWINDOW].items]==NULL)
  426.          {
  427.             MemAlloc((void **)&window[SECTIONWINDOW].list[window[SECTIONWINDOW].items],length+1);
  428.             strcpy(window[SECTIONWINDOW].list[window[SECTIONWINDOW].items],buffer);
  429.          }
  430.          length = ReadLine(buffer,BUFLEN,ndx);
  431.       }
  432.       while (length<2 || buffer[1]!='*');
  433.       
  434.       window[SECTIONWINDOW].dependingfirst[window[SECTIONWINDOW].items] = window[GROUPWINDOW].items;
  435.       
  436.       /* group loop */
  437.             
  438.       do
  439.       {
  440.          /* read group description */
  441.          
  442.          while (length<2 || buffer[1]!='=')
  443.             length = ReadLine(buffer,BUFLEN,ndx);
  444.         
  445.          window[GROUPWINDOW].list[window[GROUPWINDOW].items] = NULL;
  446.          do
  447.          {
  448.             while (length>0 && (ispunct(buffer[0])||isspace(buffer[0])))
  449.                memmove(buffer,buffer+1,length--);
  450.             while (length>0 && (ispunct(buffer[length-1])||isspace(buffer[length-1]))
  451.                             && buffer[length-1]!=')')
  452.                buffer[--length] = '\0';
  453.             if (length>0 && window[GROUPWINDOW].list[window[GROUPWINDOW].items]==NULL)
  454.             {
  455.                MemAlloc((void **)&window[GROUPWINDOW].list[window[GROUPWINDOW].items],length+1);
  456.                strcpy(window[GROUPWINDOW].list[window[GROUPWINDOW].items],buffer);
  457.             }
  458.             length = ReadLine(buffer,BUFLEN,ndx);
  459.          }
  460.          while (length<2 || buffer[1]!='=');
  461.          
  462.          /* final group with deleted files ? if so, skip it */
  463.          if (memicmp(window[GROUPWINDOW].list[window[GROUPWINDOW].items],"Files deleted",13)==0)
  464.          {
  465.             free(window[GROUPWINDOW].list[window[GROUPWINDOW].items]);
  466.             do
  467.             {
  468.                length = ReadLineEof(buffer,BUFLEN,ndx);
  469.                if (length==EOF)
  470.                   done = TRUE;
  471.             }
  472.             while (!done && (length<2 || (buffer[1]!='=' && buffer[1]!='*')));
  473.             break;
  474.          }
  475.          
  476.          window[GROUPWINDOW].dependingfirst[window[GROUPWINDOW].items] = window[FILEWINDOW].items;
  477.  
  478.          /* files loop */
  479.          
  480.          do
  481.          {         
  482.             length = ReadLineEof(buffer,BUFLEN,ndx);
  483.             if (length==EOF)
  484.                done = TRUE;
  485.             else if (length>3
  486.                      && (buffer[0]=='*' || buffer[0]=='+'
  487.                          || buffer[0]=='-' || buffer[0]==' '))
  488.             {
  489.                MemAlloc((void **)&window[FILEWINDOW].list[window[FILEWINDOW].items],length+1);
  490.                strcpy(window[FILEWINDOW].list[window[FILEWINDOW].items],buffer);
  491.                if (buffer[0]==' ' && buffer[2]==' ')
  492.                   window[FILEWINDOW].descriptionowner[window[FILEWINDOW].items]
  493.                      = lastfile;
  494.                else
  495.                {
  496.                   window[FILEWINDOW].descriptionowner[window[FILEWINDOW].items]
  497.                      = -1;
  498.                   lastfile = window[FILEWINDOW].items;
  499.                }
  500.                window[FILEWINDOW].items++;
  501.                if (window[FILEWINDOW].items==LIMITS[FILEWINDOW])
  502.                   done = TRUE;
  503.             }            
  504.          }
  505.          while (!done && (length<2 || (buffer[1]!='=' && buffer[1]!='*')));
  506.                
  507.          window[GROUPWINDOW].items++;
  508.          if (window[GROUPWINDOW].items==LIMITS[GROUPWINDOW])
  509.             done = TRUE;
  510.       }
  511.       while (!done && buffer[1]!='*');
  512.  
  513.       window[SECTIONWINDOW].items++;
  514.       if (window[SECTIONWINDOW].items==LIMITS[SECTIONWINDOW])
  515.          done = TRUE;
  516.    }
  517.    while (!done);
  518.  
  519.    fclose(ndx);
  520. }
  521.  
  522. /* load a file in the browse window
  523.    returns TRUE if file was wholly or partially loaded,
  524.    FALSE if not */
  525. bool LoadFile(short filenr)
  526. {
  527.    FILE *fp;
  528.    int   count;
  529.    int   length;
  530.    bool  done;
  531.    bool  status;
  532.  
  533.    /* free a possible previous file */
  534.    if (window[BROWSEWINDOW].items>0)
  535.    {
  536.       for (count=window[BROWSEWINDOW].items-1; count>=0; count--)
  537.       {
  538.          if (window[BROWSEWINDOW].list[count]!=FILE_NOT_FOUND
  539.              && window[BROWSEWINDOW].list[count]!=FILE_TRUNCATED)
  540.             free(window[BROWSEWINDOW].list[count]);
  541.       }
  542.    }
  543.    
  544.    window[BROWSEWINDOW].items = 0;
  545.    
  546.    fileNr = filenr;
  547.    
  548.    strncpy(fileName,window[FILEWINDOW].list[filenr]+2,12);
  549.    fileName[12] = '\0';
  550.    strtok(fileName," ");
  551.    
  552.    fp = fopen(fileName,"r");
  553.    if (fp==NULL)
  554.    {
  555.       window[BROWSEWINDOW].list[0] = FILE_NOT_FOUND;
  556.       window[BROWSEWINDOW].items = 1;
  557.       status = FALSE;
  558.    }
  559.    else
  560.    {
  561.       done = FALSE;
  562.       do
  563.       {
  564.          length = ReadLineEof(buffer,BUFLEN,fp);
  565.          if (length==-1)
  566.             done = TRUE;
  567.          else
  568.          {
  569.             window[BROWSEWINDOW].list[window[BROWSEWINDOW].items] = malloc(length+1);
  570.             if (window[BROWSEWINDOW].list[window[BROWSEWINDOW].items]==NULL)
  571.             {
  572.                window[BROWSEWINDOW].list[window[BROWSEWINDOW].items] = FILE_TRUNCATED;
  573.                done = TRUE;
  574.             }
  575.             else
  576.                strcpy(window[BROWSEWINDOW].list[window[BROWSEWINDOW].items],buffer);
  577.             window[BROWSEWINDOW].items++;
  578.             if (window[BROWSEWINDOW].items==LIMITS[BROWSEWINDOW]-1)
  579.             {
  580.                window[BROWSEWINDOW].list[window[BROWSEWINDOW].items] = FILE_TRUNCATED;
  581.                window[BROWSEWINDOW].items++;
  582.                done = TRUE;
  583.             }
  584.          }      
  585.       }
  586.       while (!done);
  587.       
  588.       fclose(fp);
  589.       
  590.       status = TRUE;
  591.    }
  592.    
  593.    return status;
  594. }
  595.  
  596. /* rebuild all dependancies of a window
  597.    recursively calls itself for deeper levels of dependancy */
  598. void BuildDependancies(int windownr)
  599. {
  600.    int depwin;
  601.    
  602.    depwin = window[windownr].dependingwindow;
  603.    if (depwin==NOWINDOW)
  604.       return;
  605.       
  606.    window[depwin].startitem = window[windownr].dependingfirst[window[windownr].activeitem];
  607.    if (window[windownr].activeitem<window[windownr].items-1)
  608.       window[depwin].enditem = window[windownr].dependingfirst[window[windownr].activeitem+1];
  609.    else
  610.       window[depwin].enditem = window[depwin].items;
  611.       
  612.    if (window[depwin].firstitem<window[depwin].startitem ||
  613.        window[depwin].firstitem+window[depwin].rows>window[depwin].enditem)
  614.    {
  615.       window[depwin].firstitem = window[depwin].startitem;
  616.       window[depwin].activeitem = window[depwin].firstitem;
  617.    }
  618.       
  619.    BuildDependancies(depwin);
  620. }
  621.  
  622. /* does window1 depend on window2 ?
  623.    recursively calls itself for deeper levels of dependancy */
  624. bool WindowDepends(int window1, int window2)
  625. {
  626.    int   depwin;
  627.    
  628.    depwin = window[window2].dependingwindow;
  629.    if (depwin==NOWINDOW)
  630.       return FALSE;
  631.    if (depwin==window1)
  632.       return TRUE;
  633.    return WindowDepends(window1,depwin);
  634. }
  635.  
  636. /* initialize windows after reading */
  637. void InitWindows(void)
  638. {   
  639.    int   count;
  640.  
  641.    /* initialize startitem and enditem for all windows */
  642.    for (count=0; count<WINDOWS; count++)
  643.    {
  644.       window[count].startitem = 0;
  645.       window[count].enditem = window[count].items;
  646.    }
  647.  
  648.    activeWindow = SECTIONWINDOW;
  649. }
  650.  
  651. /* redraw a window, if it is on screen */
  652. void DrawWindow(int windownr)
  653. {
  654.    int   x,y;
  655.    int   nr;
  656.    char  a;
  657.    bool  active;
  658.    int   titlestartx,titleendx;
  659.    
  660.    active = (windownr==activeWindow);
  661.    
  662.    if (!active && window[windownr].exclusive)
  663.       return;
  664.       
  665.    if (!active && window[activeWindow].exclusive)
  666.       return;
  667.    
  668.    /* display title */
  669.    titlestartx = window[windownr].x1
  670.                  + (window[windownr].cols-strlen(window[windownr].title)-2)/2
  671.                  - 1;
  672.    titleendx = titlestartx + strlen(window[windownr].title) + 1;
  673.    vm_xprintf(titlestartx,window[windownr].y1,window[windownr].attr,
  674.                      " %s ",window[windownr].title);
  675.  
  676.    /* draw borders */
  677.    if (active)
  678.    {
  679.       for (x=window[windownr].x1+1; x<window[windownr].x2; x++)
  680.       {
  681.          if (x<titlestartx || x>titleendx)
  682.             vm_xputch(x,window[windownr].y1,window[windownr].attr,'═');
  683.          vm_xputch(x,window[windownr].y2,window[windownr].attr,'═');
  684.       }
  685.       for (y=window[windownr].y1+1; y<window[windownr].y2; y++)
  686.       {
  687.          vm_xputch(window[windownr].x1,y,window[windownr].attr,'║');
  688.          vm_xputch(window[windownr].x2,y,window[windownr].attr,'║');
  689.       }
  690.    }
  691.    else
  692.    {
  693.       for (x=window[windownr].x1+1; x<window[windownr].x2; x++)
  694.       {
  695.          if (x<titlestartx || x>titleendx)
  696.             vm_xputch(x,window[windownr].y1,window[windownr].attr,'─');
  697.          vm_xputch(x,window[windownr].y2,window[windownr].attr,'─');
  698.       }
  699.       for (y=window[windownr].y1+1; y<window[windownr].y2; y++)
  700.       {
  701.          vm_xputch(window[windownr].x1,y,window[windownr].attr,'│');
  702.          vm_xputch(window[windownr].x2,y,window[windownr].attr,'│');
  703.       }
  704.    }
  705.  
  706.    /* draw corners */
  707.    if (active)
  708.    {
  709.       vm_xputch(window[windownr].x1,window[windownr].y1,window[windownr].attr,'╔');
  710.       vm_xputch(window[windownr].x2,window[windownr].y1,window[windownr].attr,'╗');
  711.       vm_xputch(window[windownr].x1,window[windownr].y2,window[windownr].attr,'╚');
  712.       vm_xputch(window[windownr].x2,window[windownr].y2,window[windownr].attr,'╝');
  713.    }
  714.    else
  715.    {
  716.       vm_xputch(window[windownr].x1,window[windownr].y1,window[windownr].attr,'┌');
  717.       vm_xputch(window[windownr].x2,window[windownr].y1,window[windownr].attr,'┐');
  718.       vm_xputch(window[windownr].x1,window[windownr].y2,window[windownr].attr,'└');
  719.       vm_xputch(window[windownr].x2,window[windownr].y2,window[windownr].attr,'┘');
  720.    }
  721.  
  722.    /* display the contents */   
  723.    nr = window[windownr].firstitem;
  724.    for (y=window[windownr].y1+1; y<=window[windownr].y2-1; y++,nr++)
  725.    {
  726.       if (active && window[windownr].scrollbar
  727.           && (nr==window[windownr].activeitem
  728.               || (window[windownr].allowextdescriptions
  729.                   && window[windownr].descriptionowner[nr]==window[windownr].activeitem)))
  730.          a = window[windownr].attrhigh;
  731.       else if (window[windownr].scrollbar && WindowDepends(activeWindow,windownr)
  732.           && (nr==window[windownr].activeitem
  733.               || (window[windownr].allowextdescriptions
  734.                   && window[windownr].descriptionowner[nr]==window[windownr].activeitem)))
  735.          a = window[windownr].attrselected;
  736.       else
  737.          a = window[windownr].attr;
  738.       if (nr>=window[windownr].startitem && nr<window[windownr].enditem
  739.           && strlen(window[windownr].list[nr])>window[windownr].column)
  740.       {
  741.          sprintf(buffer," %-*s",window[windownr].cols-1,
  742.                                 window[windownr].list[nr]+window[windownr].column);
  743.          if (strlen(buffer)>window[windownr].cols)
  744.             buffer[window[windownr].cols] = '\0';
  745.          vm_xprintf(window[windownr].x1+1,y,a,"%s",buffer);
  746.          if (windownr==BROWSEWINDOW && found
  747.              && findFileNr==fileNr && findLineNr==nr)
  748.             vm_paintbox(window[windownr].x1+2+findColNr,y,
  749.                         window[windownr].x1+2+findColNr+findStringLength-1,y,
  750.                         window[windownr].attrselected);
  751.       }
  752.       else
  753.          vm_paintclearbox(window[windownr].x1+1,y,window[windownr].x2-1,y,a);
  754.    }
  755. }
  756.  
  757. /* redraw all windows currently on screen */
  758. void DrawWindows(void)
  759. {
  760.    int   count;
  761.    
  762.    for (count=0; count<WINDOWS; count++)
  763.       DrawWindow(count);
  764. }
  765.  
  766. /* draw the status bar */
  767. void DrawStatusBar(void)
  768. {
  769.    vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
  770.    vm_xprintf(2,  screenRows, vm_mkcolor(YELLOW,LIGHTGRAY), "SnipView");
  771.    if (screenCols>=23)
  772.    {
  773.       vm_xprintf(12, screenRows, vm_mkcolor(RED,LIGHTGRAY),    "Enter");
  774.       vm_xprintf(17, screenRows, vm_mkcolor(BLACK,LIGHTGRAY),  "-Select");
  775.    }
  776.    if (screenCols>=32)
  777.    {
  778.       vm_xprintf(25, screenRows, vm_mkcolor(RED,LIGHTGRAY),    "ESC");
  779.       vm_xprintf(28, screenRows, vm_mkcolor(BLACK,LIGHTGRAY),  "-Prev");
  780.    }
  781.    if (screenCols>=46)
  782.    {
  783.       vm_xprintf(34, screenRows, vm_mkcolor(RED,LIGHTGRAY),    "F1..F3");
  784.       vm_xprintf(40, screenRows, vm_mkcolor(BLACK,LIGHTGRAY),  "-Window");
  785.    }
  786.    if (screenCols>=55)
  787.    {
  788.       vm_xprintf(48, screenRows, vm_mkcolor(RED,LIGHTGRAY),    "F4");
  789.       vm_xprintf(50, screenRows, vm_mkcolor(BLACK,LIGHTGRAY),  "-Notes");
  790.    }
  791.    if (screenCols>=62)
  792.    {
  793.       vm_xprintf(57, screenRows, vm_mkcolor(RED,LIGHTGRAY),    "F");
  794.       vm_xprintf(58, screenRows, vm_mkcolor(BLACK,LIGHTGRAY),  "-Find");
  795.    }
  796.    if (screenCols>=69)
  797.    {
  798.       vm_xprintf(64, screenRows, vm_mkcolor(RED,LIGHTGRAY),    "N");
  799.       vm_xprintf(65, screenRows, vm_mkcolor(BLACK,LIGHTGRAY),  "-Next");
  800.    }
  801.    if (screenCols>=79)
  802.    {
  803.       vm_xprintf(71, screenRows, vm_mkcolor(RED,LIGHTGRAY),    "AltX");
  804.       vm_xprintf(75, screenRows, vm_mkcolor(BLACK,LIGHTGRAY),  "-Quit");
  805.    }
  806. }
  807.  
  808. /* prompt for find parameters */
  809. void SelectFind(void)
  810. {
  811.    vm_xprintf(2,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),"Find: ");
  812.    findStringLength = EditString(8,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
  813.                                  findString,72);
  814.    if (findStringLength>0)
  815.    {
  816.       vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
  817.       findCase = AskYesNo(2,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
  818.                           "Case sensitive search",findCase);
  819.       vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
  820.       findWord = AskYesNo(2,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
  821.                           "Whole word search",findWord);
  822.    }
  823.    DrawStatusBar();
  824.    if (activeWindow==BROWSEWINDOW)
  825.    {
  826.       findFileNr = fileNr;
  827.       findLineNr = window[activeWindow].firstitem;
  828.       findColNr = -1;
  829.    }
  830.    else
  831.       findFileNr = -1;
  832. }
  833.  
  834. /* find next occurence of string */
  835. void FindNext(void)
  836. {
  837.    bool  done = FALSE;
  838.    short filenr;
  839.    short oldfilenr;
  840.    char *s;
  841.    int   key;
  842. #ifdef DOS
  843.    int   oldid;
  844. #endif
  845.    
  846.    vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
  847.    vm_xprintf(2,screenRows,vm_mkcolor(BLACK|BLINK,LIGHTGRAY),
  848.               "Searching...");
  849.    vm_xprintf(53,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
  850.               "(press ESC to abort search)");
  851.    
  852. #ifdef DOS
  853.    /* disable vm_kbhit() giving away timeslices,
  854.       necessary to avoid sluggish searching */
  855.    oldid = opsys_id;
  856.    opsys_id = -1;
  857. #endif
  858.  
  859.    oldfilenr = fileNr;
  860.  
  861.    if (findFileNr!=-1 && fileNr!=findFileNr)
  862.       LoadFile(findFileNr);
  863.    
  864.    findColNr++;
  865.    
  866.    found = FALSE;   
  867.  
  868.    do
  869.    {
  870.       if (findFileNr==-1 || findLineNr==window[BROWSEWINDOW].items)
  871.       {
  872.          do
  873.          {
  874.             findFileNr++;
  875.             if (findFileNr==window[FILEWINDOW].items)
  876.             {
  877.                findFileNr = -1;
  878.                done = TRUE;
  879.             }
  880.          }
  881.          while (!done && !LoadFile(findFileNr));
  882.          vm_xprintf(15,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
  883.                     "%-12s",fileName);
  884.          findLineNr = 0;
  885.          findColNr = 0;
  886.       }
  887.       s = window[BROWSEWINDOW].list[findLineNr]+findColNr;
  888.       while (!done && *s!='\0')
  889.       {
  890.          if (((findCase && memcmp(s,findString,findStringLength)==0)
  891.               || (!findCase && memicmp(s,findString,findStringLength)==0))
  892.              && (!findWord
  893.                  || ((findColNr==0 || (!isalnum(s[-1]) && s[-1]!='_'))
  894.                      && (!isalnum(s[findStringLength]) && s[findStringLength]!='_'))))
  895.          {
  896.             found = TRUE;
  897.             done = TRUE;
  898.          }
  899.          else
  900.          {
  901.             findColNr++;
  902.             s++;
  903.          }
  904.       }
  905.       if (!done)
  906.       {
  907.          findLineNr++;
  908.          findColNr = 0;
  909.       }
  910.       if (vm_kbhit())
  911.       {
  912.          key = vm_getch();
  913.          if (key==ESC)
  914.             done = TRUE;
  915.       }
  916.    }
  917.    while (!done);
  918.    DrawStatusBar();
  919.    
  920.   if (!found && activeWindow==BROWSEWINDOW && fileNr!=oldfilenr)
  921.      LoadFile(oldfilenr);
  922.      
  923. #ifdef DOS   
  924.    /* restore VidMgr's timeslicing support */
  925.    opsys_id = oldid;
  926. #endif
  927. }
  928.  
  929. /* browse through the windows interactively */
  930. void BrowseWindows(void)
  931. {
  932.    bool  done = FALSE;
  933.    short prevwinnotes;
  934.    short prevwinbrowser;
  935.    short count;
  936.    short filenr;
  937.    
  938.    do
  939.    {
  940.       BuildDependancies(activeWindow);
  941.       DrawWindows();
  942.  
  943.       switch(vm_getch())
  944.       {
  945.       case UP:
  946.          if (window[activeWindow].scrollbar)
  947.          {
  948.             if (window[activeWindow].activeitem>window[activeWindow].startitem)
  949.             {
  950.                do
  951.                {
  952.                   window[activeWindow].activeitem--;
  953.                   if (window[activeWindow].activeitem<window[activeWindow].firstitem)
  954.                      window[activeWindow].firstitem--;
  955.                }
  956.                while (window[activeWindow].allowextdescriptions
  957.                       && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  958.                       && window[activeWindow].activeitem>window[activeWindow].startitem);
  959.                if (window[activeWindow].activeitem==window[activeWindow].startitem)
  960.                {
  961.                   while (window[activeWindow].allowextdescriptions
  962.                          && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  963.                          && window[activeWindow].activeitem<window[activeWindow].enditem-1)
  964.                   {
  965.                      window[activeWindow].activeitem++;
  966.                      if (window[activeWindow].activeitem>=window[activeWindow].firstitem
  967.                                     + window[activeWindow].rows)
  968.                         window[activeWindow].firstitem++;
  969.                   }
  970.                }
  971.             }
  972.          }
  973.          else
  974.          {
  975.             if (window[activeWindow].firstitem>window[activeWindow].startitem)
  976.                window[activeWindow].firstitem--;
  977.          }
  978.          break;
  979.       case DOWN:
  980.          if (window[activeWindow].scrollbar)
  981.          {
  982.             if (window[activeWindow].activeitem<window[activeWindow].enditem-1)
  983.             {
  984.                do
  985.                {
  986.                   window[activeWindow].activeitem++;
  987.                   if (window[activeWindow].activeitem>=window[activeWindow].firstitem
  988.                          + window[activeWindow].rows)
  989.                      window[activeWindow].firstitem++;
  990.                }
  991.                while (window[activeWindow].allowextdescriptions
  992.                       && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  993.                       && window[activeWindow].activeitem<window[activeWindow].enditem-1);
  994.                if (window[activeWindow].activeitem==window[activeWindow].enditem-1)
  995.                {
  996.                   while (window[activeWindow].allowextdescriptions
  997.                          && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  998.                          && window[activeWindow].activeitem>window[activeWindow].startitem)
  999.                   {
  1000.                      window[activeWindow].activeitem--;
  1001.                      if (window[activeWindow].activeitem<window[activeWindow].firstitem)
  1002.                         window[activeWindow].firstitem--;
  1003.                   }
  1004.                }
  1005.             }
  1006.          }
  1007.          else
  1008.          {
  1009.             if (window[activeWindow].firstitem+window[activeWindow].rows
  1010.                 <window[activeWindow].enditem)
  1011.                window[activeWindow].firstitem++;
  1012.          }
  1013.          break;
  1014.       case LEFT:
  1015.          if (window[activeWindow].column>0)
  1016.          {
  1017.             window[activeWindow].column -= 8;
  1018.             if (window[activeWindow].column<0)
  1019.                window[activeWindow].column = 0;
  1020.          }
  1021.          break;
  1022.       case RIGHT:
  1023.          if (window[activeWindow].column<BUFLEN-window[activeWindow].cols)
  1024.          {
  1025.             window[activeWindow].column += 8;
  1026.             if (window[activeWindow].column>BUFLEN-window[activeWindow].cols)
  1027.                window[activeWindow].column = BUFLEN-window[activeWindow].cols;
  1028.          }
  1029.          break;
  1030.       case PGUP:
  1031.          if (window[activeWindow].firstitem>window[activeWindow].startitem
  1032.              || (window[activeWindow].scrollbar
  1033.                  && window[activeWindow].activeitem>window[activeWindow].startitem))
  1034.          {
  1035.             window[activeWindow].firstitem -= window[activeWindow].rows;
  1036.             if (window[activeWindow].firstitem<window[activeWindow].startitem)
  1037.                window[activeWindow].firstitem = window[activeWindow].startitem;
  1038.             if (window[activeWindow].scrollbar)
  1039.             {
  1040.                window[activeWindow].activeitem -= window[activeWindow].rows;
  1041.                if (window[activeWindow].activeitem<window[activeWindow].startitem)
  1042.                   window[activeWindow].activeitem = window[activeWindow].startitem;
  1043.                while (window[activeWindow].allowextdescriptions
  1044.                       && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  1045.                       && window[activeWindow].activeitem<window[activeWindow].enditem-1)
  1046.                {
  1047.                   window[activeWindow].activeitem++;
  1048.                   if (window[activeWindow].firstitem+window[activeWindow].rows
  1049.                       <window[activeWindow].enditem)
  1050.                      window[activeWindow].firstitem++;
  1051.                }
  1052.             }
  1053.          }
  1054.          break;
  1055.       case PGDN:
  1056.          if (window[activeWindow].firstitem+window[activeWindow].rows<window[activeWindow].enditem
  1057.              || (window[activeWindow].scrollbar
  1058.                  && window[activeWindow].activeitem<window[activeWindow].enditem-1))
  1059.          {
  1060.             window[activeWindow].firstitem += window[activeWindow].rows;
  1061.             if (window[activeWindow].firstitem+window[activeWindow].rows>window[activeWindow].enditem)
  1062.                window[activeWindow].firstitem = window[activeWindow].enditem-window[activeWindow].rows;
  1063.             if (window[activeWindow].firstitem<window[activeWindow].startitem)
  1064.                window[activeWindow].firstitem = window[activeWindow].startitem;
  1065.             if (window[activeWindow].scrollbar)
  1066.             {
  1067.                window[activeWindow].activeitem += window[activeWindow].rows;
  1068.                if (window[activeWindow].activeitem>window[activeWindow].enditem-1)
  1069.                   window[activeWindow].activeitem = window[activeWindow].enditem-1;
  1070.                while (window[activeWindow].allowextdescriptions
  1071.                       && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  1072.                       && window[activeWindow].activeitem>window[activeWindow].startitem)
  1073.                {
  1074.                   window[activeWindow].activeitem--;
  1075.                   if (window[activeWindow].activeitem<window[activeWindow].firstitem)
  1076.                      window[activeWindow].firstitem--;
  1077.                }
  1078.             }
  1079.          }
  1080.          break;
  1081.       case HOME:
  1082.          if (window[activeWindow].firstitem>window[activeWindow].startitem
  1083.              || (window[activeWindow].scrollbar
  1084.                  && window[activeWindow].activeitem>window[activeWindow].startitem))
  1085.          {
  1086.             window[activeWindow].firstitem = window[activeWindow].startitem;
  1087.             if (window[activeWindow].scrollbar)
  1088.             {
  1089.                window[activeWindow].activeitem = window[activeWindow].startitem;
  1090.                while (window[activeWindow].allowextdescriptions
  1091.                       && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  1092.                       && window[activeWindow].activeitem<window[activeWindow].enditem-1)
  1093.                {
  1094.                   window[activeWindow].activeitem++;
  1095.                   if (window[activeWindow].firstitem+window[activeWindow].rows
  1096.                       <window[activeWindow].enditem)
  1097.                      window[activeWindow].firstitem++;
  1098.                }
  1099.             }
  1100.          }
  1101.          break;
  1102.       case END:
  1103.          if (window[activeWindow].firstitem+window[activeWindow].rows<window[activeWindow].enditem
  1104.              || (window[activeWindow].scrollbar
  1105.                  && window[activeWindow].activeitem<window[activeWindow].enditem-1))
  1106.          {
  1107.             window[activeWindow].firstitem = window[activeWindow].enditem-window[activeWindow].rows;
  1108.             if (window[activeWindow].firstitem<window[activeWindow].startitem)
  1109.                window[activeWindow].firstitem = window[activeWindow].startitem;
  1110.             if (window[activeWindow].scrollbar)
  1111.             {
  1112.                window[activeWindow].activeitem = window[activeWindow].enditem-1;
  1113.                while (window[activeWindow].allowextdescriptions
  1114.                       && window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
  1115.                       && window[activeWindow].activeitem>window[activeWindow].startitem)
  1116.                {
  1117.                   window[activeWindow].activeitem--;
  1118.                   if (window[activeWindow].activeitem<window[activeWindow].firstitem)
  1119.                      window[activeWindow].firstitem--;
  1120.                }
  1121.             }
  1122.          }
  1123.          break;
  1124.       case F1:
  1125.          window[activeWindow].column = 0;
  1126.          activeWindow = SECTIONWINDOW;
  1127.          break;
  1128.       case F2:
  1129.          window[activeWindow].column = 0;
  1130.          activeWindow = GROUPWINDOW;
  1131.          break;
  1132.       case F3:
  1133.          window[activeWindow].column = 0;
  1134.          activeWindow = FILEWINDOW;
  1135.          break;
  1136.       case F4:
  1137.          if (activeWindow!=NOTEWINDOW)
  1138.          {
  1139.             prevwinnotes = activeWindow;
  1140.             window[activeWindow].column = 0;
  1141.             activeWindow = NOTEWINDOW;
  1142.             window[activeWindow].firstitem = 0;
  1143.          }
  1144.          break;
  1145.       case ENTER:
  1146.          if (window[activeWindow].dependingwindow!=NOWINDOW)
  1147.          {
  1148.             window[activeWindow].column = 0;
  1149.             activeWindow = window[activeWindow].dependingwindow;
  1150.          }
  1151.          else if (activeWindow==FILEWINDOW)
  1152.          {
  1153.             window[activeWindow].column = 0;
  1154.             filenr = window[FILEWINDOW].activeitem;
  1155.             if (window[FILEWINDOW].descriptionowner[filenr]!=-1)
  1156.                filenr = window[FILEWINDOW].descriptionowner[filenr];
  1157.             LoadFile(filenr);
  1158.             window[BROWSEWINDOW].startitem = 0;
  1159.             window[BROWSEWINDOW].enditem = window[BROWSEWINDOW].items;
  1160.             window[BROWSEWINDOW].firstitem = 0;
  1161.             window[BROWSEWINDOW].column = 0;
  1162.             prevwinbrowser = activeWindow;
  1163.             activeWindow = BROWSEWINDOW;
  1164.          }
  1165.          break;
  1166.       case ESC:
  1167.          switch(activeWindow)
  1168.          {
  1169.          case GROUPWINDOW:
  1170.             window[activeWindow].column = 0;
  1171.             activeWindow = SECTIONWINDOW;
  1172.             break;
  1173.          case FILEWINDOW:
  1174.             window[activeWindow].column = 0;
  1175.             activeWindow = GROUPWINDOW;
  1176.             break;
  1177.          case BROWSEWINDOW:
  1178.             window[activeWindow].column = 0;
  1179.             activeWindow = prevwinbrowser;
  1180.             break;
  1181.          case NOTEWINDOW:
  1182.             window[activeWindow].column = 0;
  1183.             activeWindow = prevwinnotes;
  1184.             break;
  1185.          }
  1186.          break;
  1187.       case 'F':
  1188.       case 'f':
  1189.          window[activeWindow].column = 0;
  1190.          SelectFind();
  1191.          /* deliberate fallthrough */
  1192.       case 'N':
  1193.       case 'n':
  1194.          if (findStringLength>0)
  1195.          {
  1196.             FindNext();
  1197.             if (found)
  1198.             {
  1199.                window[BROWSEWINDOW].startitem = 0;
  1200.                window[BROWSEWINDOW].enditem = window[BROWSEWINDOW].items;
  1201.                window[BROWSEWINDOW].firstitem = 0;
  1202.                window[BROWSEWINDOW].column = 0;
  1203.                if (activeWindow!=BROWSEWINDOW)
  1204.                   prevwinbrowser = activeWindow;
  1205.                activeWindow = BROWSEWINDOW;
  1206.                window[activeWindow].firstitem = findLineNr
  1207.                                                 - window[activeWindow].rows/2;
  1208.                if (window[activeWindow].firstitem<window[activeWindow].startitem)
  1209.                   window[activeWindow].firstitem = window[activeWindow].startitem;
  1210.             }
  1211.          }
  1212.          break;
  1213.       case ALTX:
  1214.          done = TRUE;
  1215.          break;     
  1216.       }      
  1217.    }
  1218.    while (!done);
  1219. }
  1220.  
  1221. /* initialize vidmgr, clear screen, draw status bar & scale windows */
  1222. void InitScreen(void)
  1223. {
  1224.    int   count;
  1225.    
  1226.    vm_init();
  1227.    screenCols = vm_getscreenwidth();
  1228.    screenRows = vm_getscreenheight();
  1229.    
  1230.    vm_setcursorstyle(CURSORHIDE);
  1231.    vm_setattr(vm_mkcolor(LIGHTGRAY,BLACK));
  1232.    vm_clrscr();
  1233.    DrawStatusBar();
  1234.    
  1235.    for (count=0; count<WINDOWS; count++)
  1236.    {
  1237.       window[count].x1 = 1 + ((window[count].x1 - 1) * screenCols/80);
  1238.       window[count].y1 = 1 + ((window[count].y1 - 1) * screenRows/25);
  1239.       if (window[count].x2==80) /* always round up to edge of screen */
  1240.          window[count].x2 = screenCols;
  1241.       else
  1242.          window[count].x2 = screenCols - ((80 - window[count].x2)
  1243.                                           * screenCols/80);
  1244.       if (window[count].y2==24) /* leave a line for the status bar */
  1245.          window[count].y2 = screenRows - 1;
  1246.       else
  1247.          window[count].y2 = screenRows - ((25 - window[count].y2)
  1248.                                           * screenRows/25);
  1249.       window[count].cols = window[count].x2 - window[count].x1 - 1;
  1250.       window[count].rows = window[count].y2 - window[count].y1 - 1;
  1251.    }
  1252. }
  1253.  
  1254. /* deinitialize vidmgr & clear screen */
  1255. void DeInitScreen(void)
  1256. {
  1257.    vm_setattr(LIGHTGRAY);
  1258.    vm_clrscr();
  1259.    vm_setcursorstyle(CURSORNORM);
  1260.    vm_done();
  1261. }
  1262.  
  1263. int main(int argc, char *argv[])
  1264. {
  1265.    char *indexfile;
  1266.    
  1267.    if (argc>1)
  1268.    {
  1269.       if (argc>2 || strchr(argv[1],'?')!=NULL)
  1270.       {
  1271.          printf("SnipView snippets browser by Tom Torfs\n\n");
  1272.          printf("Usage: SNIPVIEW [indexfile]\n\n");
  1273.          printf("Default is %s.\n",DEFAULT_INDEXFILE);
  1274.          return EXIT_FAILURE;
  1275.       }
  1276.       indexfile = argv[1];
  1277.    }
  1278.    else
  1279.       indexfile = DEFAULT_INDEXFILE;
  1280.    
  1281.    ReadIndexFile(indexfile);
  1282.    
  1283.    InitWindows();
  1284.    
  1285.    InitScreen();
  1286.    
  1287.    BrowseWindows();
  1288.    
  1289.    DeInitScreen();
  1290.    
  1291.    return EXIT_SUCCESS;   
  1292. }
  1293.